package org.example.exception;

import lombok.extern.slf4j.Slf4j;
import org.example.controller.CommonResponse;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author Aaron
 * @since 2021/9/6 14:03
 * <p>描述：自定义全局异常</p>
 */
@Slf4j
@RestControllerAdvice
public class CustomExceptionHandler {

    /**
     * 请求参数校验失败异常捕获
     *
     * @param e 使用 @Valid + BindingResult 校验参数，参数不符合规则时抛出异常
     * @return 异常返回结果
     */
    @ExceptionHandler({BindException.class, MethodArgumentNotValidException.class})
    public CommonResponse<?> validationBodyException(HttpServletRequest request, Exception e) {
        BindingResult result = null;
        if (e instanceof MethodArgumentNotValidException) {
            result = ((MethodArgumentNotValidException) e).getBindingResult();
        } else if (e instanceof BindException) {
            result = ((BindException) e).getBindingResult();
        }

        // 对校验错误信息进行封装，并输出到日志
        if (result == null || !result.hasErrors()) {
            return CommonResponse.error(request.getRequestURI().substring(request.getContextPath().length()));
        }

        final Map<String, String> collect = result.getAllErrors().stream().collect(Collectors.toMap(
                t -> ((FieldError) t).getField(),
                t -> StringUtils.isEmpty(t.getDefaultMessage()) ? "" : t.getDefaultMessage())
        );
        return CommonResponse.error("接口 {} 参数不合法：{}",
                request.getRequestURI().substring(request.getContextPath().length()), collect);
    }

    /**
     * 全局异常捕获
     *
     * @param exception 全局异常
     * @return 全局异常捕获后返回结果整理
     */
    @ExceptionHandler(Exception.class)
    public CommonResponse<?> exceptionHandler(HttpServletRequest request, Exception exception) {
        log.error("全局异常捕获：{} {}", request.getRequestURI(), exception);
        return CommonResponse.error(
                request.getRequestURI().substring(request.getContextPath().length()) + " " + exception.getMessage());
    }

}
